package com.jabber.utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;

import com.jabber.bot.JabberBot;
import com.jabber.listeners.MessageList;

public class MessageUtils {

	private BotConfig config;
	private List<String> admins;
	private Roster roster;
	private String host;
	private ChatManager chatManager;
	private Map<String,String> groups;

	private static Logger logger = Logger.getLogger(MessageUtils.class);
	
	public MessageUtils(BotConfig config, Roster roster, ChatManager chatManager) {
		this.config = config;
		this.roster = roster;
		this.admins = config.getAdmins();
		this.host = config.getHost();
		this.chatManager = chatManager;
		
		groups = new HashMap<String,String>();
		groups.put("all", "all");
		groups.put("mc", "Mercenary Coalition");
		groups.put("bsc", "Black Storm Cartel");
		groups.put("l2k", "Licence To Kill");
		groups.put("snipes", "Snipes Incorporated UK");
		groups.put("good", "Greater Order Of Destruction");
		groups.put("agrsr", "The Aggressors");
		groups.put("leadership", "Leadership");		
	}

	public void parseMessage(Chat chat, Message message)
			throws NotConnectedException, XMPPException, IOException {
		String sender = chat.getParticipant();
		String body = message.getBody();

		sender = trimUser(sender);

		if (admins.contains(sender)) { // Admin message
			logger.info("Admin message from: " + sender + ": " + body);
			if (body.equals("exit")) { // Quit
				JabberBot.exit();
			} else if (body.startsWith("ping ")) { // Send a broadcast
				body = body.substring(5);
				String group = body.substring(0, body.indexOf(' '));
				String text = body.substring(body.indexOf(' ') + 1);

				logger.info("Ping for " + group + ": " + text);

				broadcast(roster, sender, group, text);
			} else if(body.equals("listadmins")) {
				StringBuilder sb = new StringBuilder();
				sb.append("The following users are administrators:\r\n");
				
				for(String admin : admins) {
					sb.append(admin);
					sb.append("\r\n");
				}
				chat.sendMessage(sb.toString());
			} else if(body.startsWith("removeadmin")) {
				String admin = body.substring(body.indexOf(' ') + 1);

				if(!admins.contains(admin + "@" + host)) {
					chat.sendMessage("User is not an admin.");
				} else if(roster.contains(admin + "@" + host)) {
					admins.remove(admin + "@" + host);
					config.setAdmins(admins);
					chat.sendMessage("User successfully removed.");
					
					Chat c2 = chatManager.createChat(admin + "@" + host, new MessageList());
					c2.sendMessage("You have been removed as an admin by " + sender + ".");
					c2.close();
					
					logger.info("Admin removed by " + sender + ": " + admin);
				} else {
					chat.sendMessage("User not recognized.");
				}
			} else if (body.startsWith("addadmin")) {
				String admin = body.substring(body.indexOf(' ') + 1);
				
				if(admins.contains(admin + "@" + host)) {
					chat.sendMessage("User is already an admin.");
				} else if(roster.contains(admin + "@" + host)) {
					admins.add(admin + "@" + host);
					config.setAdmins(admins);
					chat.sendMessage("User successfully added.");
					
					Chat c2 = chatManager.createChat(admin + "@" + host, new MessageList());
					c2.sendMessage("You have been added as an admin by " + sender + ". Type \"help\" to see a list of available commands.");
					c2.close();
					
					logger.info("Admin added by " + sender + ": " + admin);
				} else {
					chat.sendMessage("User not recognized.");
				}
			} else if (body.startsWith("help")) {
				StringBuilder sb = new StringBuilder();
				sb.append("\r\nThe following is a list of commands, their format, and their description.\r\n");
				sb.append("help - displays this help text.\r\n");
				sb.append("exit - shuts down the bot.\r\n");
				sb.append("ping <group> <message> - Sends <message> to all online users in <group>.\r\n");
				sb.append("\tValid groups are:\r\n");
				sb.append("\tall - Everyone on the server\r\n");
				sb.append("\tmc - Mercenary Coalition\r\n");
				sb.append("\tbsc - Black Storm Cartel\r\n");
				sb.append("\tl2k - Licence To Kill\r\n");
				sb.append("\tsnipes - Snipes Incorporated UK\r\n");
				sb.append("\tgood - Greater Order Of Destruction\r\n");
				sb.append("\tagrsr - The Aggressors\r\n");
				sb.append("\tleadership - Leadership\r\n");
				sb.append("addadmin <username> - Adds a user to the list of admins. Only include the portion before the @.\r\n");
				sb.append("removeadmin <username> - Removes a user from the list of admins. Only include the portion before the @.\r\n");
				sb.append("listadmins - Prints the current list of admins.\r\n");
				chat.sendMessage(sb.toString());
			} else { // Send help text
				chat.sendMessage("Command not recognized. Type \"help\" to see available commands.");
			}
		} else { // Non-admin message
			logger.info("Received message from " + sender + ": " + body);
			chat.sendMessage("You are not an administrator. Message disregarded.");
		}
	}

	public void sendMessage(String user, String text)
			throws NotConnectedException {
		Chat chat = chatManager.createChat(user, new MessageList());
		Message message = new Message();
		message.setBody(text);

		chat.sendMessage(message);
		chat.close();
	}

	public void broadcast(Roster roster, String sender, String group,
			String text) throws NotConnectedException {

		group = groups.get(group);
		
		Collection<RosterEntry> entries;
		if (group.equals("all"))
			entries = roster.getEntries();
		else
			entries = roster.getGroup(group).getEntries();

		ArrayList<String> users = new ArrayList<String>();
		Presence presence;
		String user;

		for (RosterEntry entry : entries) {
			user = entry.getUser();
			presence = roster.getPresence(user);
			if (Presence.Type.available == presence.getType())
				users.add(user);
		}

		logger.info("Online members (" + users.size() + "):");
		logger.info(users);

		StringBuilder sb = new StringBuilder();
		sb.append("==BROADCAST MESSAGE== ");
		sb.append(text);
		sb.append("\r\nSent by ");
		sb.append(sender);
		sb.append(" to ");
		sb.append(group);
		sb.append(".");

		for (String recipient : users) {
			sendMessage(recipient, sb.toString());
		}
	}

	private String trimUser(String user) {
		int last = user.lastIndexOf("@" + host);
		return user.substring(0, last + host.length() + 1);
	}

}
